/***********************************************************************
    filename:   CEGUIDirect3D9TextureTarget.cpp
    created:    Fri Feb 13 2009
    author:     Paul D Turner
*************************************************************************/

#define NOMINMAX
#include "hgeTextureTarget.h"
#include "hgeExceptions.h"
#include "hgeLogger.h"
#include "hgeRenderQueue.h"
#include "hgeGeometryBuffer.h"
#include "hgeRenderer.h"
#include "hgeTexture.h"

//----------------------------------------------------------------------------//
const float TextureTarget::DEFAULT_SIZE = 128.0f;

//----------------------------------------------------------------------------//
TextureTarget::TextureTarget(Renderer& owner) :
    RenderTarget(owner),
    d_texture(0),
    d_surface(0)
{
    // this essentially creates a 'null' Texture
    d_CEGUITexture = &d_owner.createTexture(0);

    // setup area and cause the initial texture to be generated.
    declareRenderSize(DEFAULT_SIZE, DEFAULT_SIZE);
}

//----------------------------------------------------------------------------//
TextureTarget::~TextureTarget()
{
    cleanupRenderTexture();
    d_owner.destroyTexture(*d_CEGUITexture);
}

//----------------------------------------------------------------------------//
void TextureTarget::declareRenderSize(UINT width, UINT height)
{
    // exit if current size is enough
	UINT orgWidth = d_area.getWidth();
	UINT orgHeight = d_area.getHeight();
    if ((orgWidth >= width) && (orgHeight >= height))
        return;
	
	hgeRect rect;
	rect.setWidth(width);
	rect.setHeight(height);	
    setArea(rect);
    resizeRenderTexture();
    clear();
}

//----------------------------------------------------------------------------//
bool TextureTarget::isImageryCache() const
{
    return true;
}

//----------------------------------------------------------------------------//
void TextureTarget::activate()
{
    enableRenderTexture();
	RenderTarget::activate();
}

//----------------------------------------------------------------------------//
void TextureTarget::deactivate()
{
    RenderTarget::deactivate();
    disableRenderTexture();
}

//----------------------------------------------------------------------------//
void TextureTarget::clear()
{
    // switch to targetting our texture
    enableRenderTexture();
    // Clear it.
    d_device->Clear(0, 0, D3DCLEAR_TARGET, D3DCOLOR_ARGB(0, 0, 0, 0), 1.0f, 0);
    // switch back to rendering to previous target
    disableRenderTexture();
}

//----------------------------------------------------------------------------//
Texture& TextureTarget::getTexture() const
{
    return *d_CEGUITexture;
}

//----------------------------------------------------------------------------//
void TextureTarget::initialiseRenderTexture()
{
    Size tex_sz = d_owner.getAdjustedSize(d_area.getWidth(), d_area.getHeight());

    d_device->CreateTexture(tex_sz.d_x, tex_sz.d_y,
                            1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8,
                            D3DPOOL_DEFAULT, &d_texture, 0);

    d_texture->GetSurfaceLevel(0, &d_surface);

    // wrap the created texture with the Texture
    d_CEGUITexture->setTexture(d_texture);
    d_CEGUITexture->setOriginalDataSize(d_area.getWidth(), d_area.getHeight());
}

//----------------------------------------------------------------------------//
void TextureTarget::resizeRenderTexture()
{
    cleanupRenderTexture();
    initialiseRenderTexture();
}

//----------------------------------------------------------------------------//
void TextureTarget::cleanupRenderTexture()
{
    if (d_surface)
    {
        d_surface->Release();
        d_surface = 0;
    }
    if (d_texture)
    {
        d_CEGUITexture->setTexture(0);
        d_texture->Release();
        d_texture = 0;
    }
}

//----------------------------------------------------------------------------//
void TextureTarget::enableRenderTexture()
{
    LPDIRECT3DSURFACE9 oldSurface;
    d_device->GetRenderTarget(0, &oldSurface);

    if (oldSurface && oldSurface != d_surface)
    {
        d_prevColourSurface = oldSurface;
        d_device->SetRenderTarget(0, d_surface);
    }
    else if (oldSurface)
        oldSurface->Release();
}

//----------------------------------------------------------------------------//
void TextureTarget::disableRenderTexture()
{
    d_device->SetRenderTarget(0, d_prevColourSurface);
    d_prevColourSurface->Release();
}

//----------------------------------------------------------------------------//
bool TextureTarget::isRenderingInverted() const
{
    return false;
}

//----------------------------------------------------------------------------//
void TextureTarget::preD3DReset()
{
    if (d_surface)
    {
        d_surface->Release();
        d_surface = 0;
    }

    if (d_CEGUITexture)
        d_CEGUITexture->preD3DReset();

    if (d_texture)
    {
        d_texture->Release();
        d_texture = 0;
    }
}

//----------------------------------------------------------------------------//
void TextureTarget::postD3DReset()
{
    if (!d_CEGUITexture)
        return;

    // this will recreate the texture
    d_CEGUITexture->postD3DReset();
    // we now obtain a reference to that created texture
    d_texture = d_CEGUITexture->getTexture();
    if (d_texture)
    {
        d_texture->AddRef();
        // now obtain the surface
        d_texture->GetSurfaceLevel(0, &d_surface);
    }
}